#include <pcap.h>
#include <string.h>
#include <stdio.h>
#include <netinet/in.h>
#include <linux/ip.h>
#include <netinet/ip6.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/if_ether.h>
#include <time.h>

#include "pcap_process.h"
#include<mysql/mysql.h>
#include"uthash.h"
#include"use_hash.h"
#include"buff_queue.h"
#include"distriethhdr.h"

#define LINK_OFFSET 14 /* DLT_EN10_MB */
extern MYSQL mysql;
extern unsigned long raw_packet_count;
extern unsigned long ipv4_packet_count;
#define TIME_INTERVAL 5
#define TIME_TABLE_INTERVAL 3600
static unsigned long time1 = 0;
static unsigned long time2 = 0;
static unsigned long table_time1 = 0; 
static unsigned long table_time2 = 0; 
static char table_name[128] = {'\0'};

static int table_id = 0;

extern head;
extern Buffer_queue;

static void do_processing(const struct iphdr *iph, unsigned short ipsize, unsigned short rawsize)
{
//	printf("begin do_process.");

	int res;
	table_time2 = time(NULL);
	
	if (table_time2 >= table_time1 + TIME_TABLE_INTERVAL) {
		char cmd[1024] = {'\0'};

		sprintf(table_name, "part_partion%lu", table_time2);

		sprintf(cmd, "create table %s(ipv4PacketsCount bigint, rawPacketsCount bigint)", table_name);
		res = mysql_query(&mysql,cmd);
		if (res) {
			printf("sql_query error: %s\n",mysql_error(&mysql));
		}

		sprintf(cmd, "insert into pcapTableInfo values(%d,'%s')", table_id, table_name);
		table_id++;
		res = mysql_query(&mysql,cmd);
		if (res) {
			printf("sql_query error:%s\n", mysql_error(&mysql));
		}

		table_time1 = table_time2;
	}
	 printf("%d",iph->ihl);

	if (iph->version == 4 && ipsize >= sizeof(struct iphdr)) {
		ipv4_packet_count++;
		int ihl=iph->ihl;

		if(iph->protocol==17)
		{
			printf("UDP\n");
			
		}

		/* Hope with SMP's help, it won't take too much time... */	
/*		void *data = s_malloc(ipsize);
		if (data == NULL) {
			printf("No enough mem.");
			return;
		}

		memcpy(data, iph, ipsize);


		time2 = time(NULL);

		if (time2 >= time1 + TIME_INTERVAL) {
			char cmd[1024] = {'\0'};

			sprintf(cmd, "insert into %s values(%lu, %lu)", table_name, ipv4_packet_count, raw_packet_count);
			//printf("%s\n", cmd);
			res = sql_query(cmd);
			if (res) {
				printf("sql_query error: %d, %s\n", sql_errorno(), sql_error());
			}

			time1 = time2;
		}*/

	}

}

void pcap_task_packet_process(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
{
//	printf("begin pcap_task_packet_process.");
/*
	struct ether_header *eth_header;

	eth_header = (struct ether_header*)packet;

	int i=0;	
	for(i=0;i<ETH_ALEN;i++)
	{
		printf("%c",eth_header[i]);
	}

//	S_Mac=eth_header->ether_shost;
	
//	char * D_Mac=eth_header->ether_dhost;
	
//	printf("source_mac :%s",S_Mac);
	
//	printf("destinate_mac: %s",D_Mac);
*/	
	const struct ethhdr *ethernet = (struct ethhdr *)packet;
	
	int i=0;
/*	printf("Source Mac:");


	for(i=0;i<ETH_ALEN;i++)
        {
              printf("%x:",ethernet->h_source[i]);
        }
        printf("\n");

	printf("Destination Mac:");

	for(i=0;i<ETH_ALEN;i++)
	{
		printf("%x:",ethernet->h_dest[i]);
	}
	printf("\n");
*/
	struct iphdr *iph = (struct iphdr *)&packet[sizeof(struct ethhdr)];

	raw_packet_count++;

	unsigned short type = ethernet->h_proto;

	if ((type == htons(ETH_P_IP)) 
			&& header->caplen >= sizeof(struct ethhdr)) {
		if (header->caplen < header->len) {
			static unsigned char cap_warning_used = 0;
			if (cap_warning_used == 0) {
				printf("packet capture size is smaller than pcasket size.");
				cap_warning_used = 1;
			}
		}

		if (header->len >= (sizeof(struct ethhdr) + sizeof(struct iphdr)))
		{
			
			printf("source ip :%s\n",inet_ntoa(iph->saddr));
			printf("destination ip :%s\n",inet_ntoa(iph->daddr));
			printf("ip_header len: %d\n",4*(iph->ihl));
			


			if (iph->version == 4)
			{
                		int ihl=iph->ihl;
				
//				printf("source ip :%s\n",(char*)inet_ntoa(iph->saddr));
//		                printf("destination ip :%s\n",(char*)inet_ntoa(iph->daddr));

				short int source_port=0;
				short int destinat_port=0;				

				int flag=0;
                		if(iph->protocol==17)
                		{
					flag=1;
                        		printf("UDP\n");
                        		source_port=(short int)(packet+ihl+14);
					destinat_port=(short int)(packet+ihl+16);

					printf("source port :%d\n",ntohs(source_port));
					
					printf("desination port :%d\n",ntohs(destinat_port));					

                		}
				
				if(iph->protocol==6)
                                {
					flag=1;
                                        printf("TCP\n");
					
                                        source_port=(short int)(packet+ihl+14);
                                        destinat_port=(short int)(packet+ihl+16);
                                        printf("source port :%d\n",ntohs(source_port));


                                        printf("desination port :%d\n",ntohs(destinat_port));

                                }

				if(flag==1)
				{
					record_t *p=NULL;
					p=(record_t *)malloc(sizeof(record_t));
					memset(p,0,sizeof(record_t));
					struct buff_queue_node *bu_queue_node;
					int i=0;
					struct distriethhdr *dishdr;
					int dishdr_len=sizeof(struct distriethhdr);
					dishdr=(struct distriethhdr *)malloc(dishdr_len);

					//header_len is the size of struct pcap_pkthdr that contain the information of core's pcap. 
					int header_len=sizeof(struct pcap_pkthdr);
					
					//head_len is the protocol that we use to dispatch the packet to client.
					int head_len=dishdr_len +header_len;

					bu_queue_node=(struct buff_queue_node *)malloc(sizeof(struct buff_queue_node));
	
					memset(bu_queue_node,0,sizeof(struct buff_queue_node));
										

					bu_queue_node->key.saddr=p->key.saddr=iph->saddr;
					bu_queue_node->key.daddr=p->key.daddr=iph->daddr;

					bu_queue_node->key.source_port=p->key.source_port=source_port;

					bu_queue_node->key.dest_port=p->key.dest_port=destinat_port;

					bu_queue_node->key.protocol=p->key.protocol=iph->protocol;
					//so the packet's len is the length of header and the packet 					
					bu_queue_node->packet=(char *)malloc(header->len+head_len);
					
					bu_queue_node->packet_len=header->len+head_len;
			
					
					//next is to construct the header to struct distriethhdr.
					
					dishdr->version=0;
					dishdr->client_num=0;
					dishdr->dheader_len=head_len;
					dishdr->remainning=0;
					
					//next is to give the value of distribute header to packet of socket.
					
					for(i=0;i<dishdr_len;i++)
					{
						bu_queue_node->packet[i]=((char *)dishdr)[i];
					}

					for(i=0;i<header_len;i++)
					{
						bu_queue_node->packet[i+ dishdr_len]=((char *)header)[i];						
					}

					for(i=0;i<header->len;i++)
					{
						bu_queue_node->packet[i+head_len]=packet[i];		
					
					}
						
					bu_queue_node->arrive_time=time(NULL);
					
					buff_queue_add(Buffer_queue,bu_queue_node);						
					
					bu_queue_node->next=p->next=NULL;
					
					p->dispatch_id=-1;
					add_hash(&head,p);

					printf("now hash number %d\n",count_hash(head));
				}
			}
			printf("\n\n\n");

			//do_processing(iph, header->len - sizeof(struct ethhdr), header->len);
		}
	}
		
	return;
}

